
/**  
* @Title: WxAccountUtil.java
* @Package com.third.wx.gzh.util
* @Description: 
* @author likai
* @date 2017年10月13日
* @version V1.0  
*/

package com.third.utils.wx;

import java.io.File;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.supers.enums.Charset;
import com.third.base.wx.AES;
import com.third.base.wx.WxXcxPKCS7Encoder;
import com.utils.date.CalendarUtil;
import com.utils.file.FileUtil;
import com.utils.http.HttpClientUtil;
import com.utils.md5.Base64;

/**
 * @ClassName: WxAccountUtil
 * @Description: 公众号、小程序工具
 * @author likai
 * @date 2017年10月13日
 *
 */

public class WxUtil{
	public static Logger log = LoggerFactory.getLogger(WxUtil.class);
	// public static Map<String, Map<String, Object>> wxConfig=new
	// HashMap<String, Map<String,Object>>();

	private WxConfig wxConfig;
	// --------------------公众号
	private String access_query_token_url = "https://api.weixin.qq.com/cgi-bin/token";// 获取访问接口token，为所有访问必须的参数
	private String access_token_url = "https://api.weixin.qq.com/sns/oauth2/access_token";// 获取登录授权token
	private String refresh_token_url = "https://api.weixin.qq.com/sns/oauth2/refresh_token";// 刷新token
	private String userinfo_url = "https://api.weixin.qq.com/sns/userinfo";// 获取用户信息，无需用户关注了平台，需要OAuth2.0鉴权
	private String focus_user_url = "https://api.weixin.qq.com/cgi-bin/user/info";// 获取已关注平台的用户信息，用户需要关注了公众号才能获取
	private String qr_code = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=";// 微信二维码获取
	private String qr_code_pic = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=";// 微信二维码获取
	private String shorturl = "https://api.weixin.qq.com/cgi-bin/shorturl?access_token=";// 长链接转短链接接口
	private String send_msg = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=";// 发送公众号模板消息接口
	private String custom_msg = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=";// 发送公众号客服消息接口
	private String jsapi_ticket = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=";// 获取微信JS接口的临时票据
	private String getFileUrl = "https://api.weixin.qq.com/cgi-bin/media/get?access_token=";// 下载微信JSSDK上传的临时文件
	private String getNiceFileUrl = "https://api.weixin.qq.com/cgi-bin/media/get/jssdk?access_token=";// 下载微信JSSDK上传的高清临时语音文件

	// --------------------小程序
	private String getwxacodeunlimit = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=";// 获取小程序二维码（适用于需要的码数量极多）
	private String send_mic_msg = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=";// 发送微信小程序模板消息接口

	private static WxUtil wxUtil;

	private String create_wx_menu = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=";// 微信菜单创建
	// private String
	// del_wx_menu="https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=";//微信菜单删除

	private String authorizeUrl="https://open.weixin.qq.com/connect/oauth2/authorize";//公众号授权登录链接

	private WxUtil(WxConfig wxConfig) {
		super();
		this.wxConfig = wxConfig;

	}

	public static WxUtil init(WxConfig wxConfig) {
		if (wxUtil == null) {
			wxUtil = new WxUtil(wxConfig);
		}
		return wxUtil;
	}

	/*
	 * @Description:获取公众号授权登录token，有效期是7200秒
	 * 
	 * @return:
	 * 
	 * access_token 网页授权接口调用凭证,注意：此access_token与基础支持的access_token不同 expires_in
	 * access_token接口调用凭证超时时间，单位（秒） refresh_token 用户刷新access_token openid
	 * 用户唯一标识，请注意，在未关注公众号时，用户访问公众号的网页，也会产生一个用户和公众号唯一的OpenID scope
	 * 用户授权的作用域，使用逗号（,）分隔 flag 接口调用状态
	 *
	 */
	@SuppressWarnings("unchecked")
	public Map<String, Object> getGzhOauth2Token(String code) {
		try {
			String url = access_token_url + "?appid=" + wxConfig.getAppID() + "&secret=" + wxConfig.getAppSecret()
					+ "&code=" + code + "&grant_type=authorization_code";
			Map<String, Object> response = (Map<String, Object>) HttpClientUtil.httpJson.getClient(url, Charset.UTF8,
					Map.class);
			if (response.get("errcode") == null) {
				return response;
			} else {
				log.info(response.toString());
				return null;
			}
		} catch (Exception e) {
			log.info("换取网页授权access_token失败");
			return null;
		}
	}

	/*
	 * @Description:刷新公众号授权登录token
	 * 
	 * @return:
	 * 
	 * access_token 网页授权接口调用凭证,注意：此access_token与基础支持的access_token不同 expires_in
	 * access_token接口调用凭证超时时间，单位（秒） refresh_token 用户刷新access_token openid
	 * 用户唯一标识，请注意，在未关注公众号时，用户访问公众号的网页，也会产生一个用户和公众号唯一的OpenID scope
	 * 用户授权的作用域，使用逗号（,）分隔 flag 接口调用状态
	 *
	 */
	@SuppressWarnings("unchecked")
	public Map<String, Object> refreshGzhOauth2Token(String refresh_token) {
		try {
			String url = refresh_token_url + "?appid=" + wxConfig.getAppID()
					+ "&grant_type=refresh_token&refresh_token=" + refresh_token;
			Map<String, Object> response = (Map<String, Object>) HttpClientUtil.httpJson.getClient(url, Charset.UTF8,
					Map.class);
			if (response.get("errcode") == null) {
				return response;
			} else {
				log.info(response.toString());
				return null;
			}
		} catch (Exception e) {
			log.info("刷新网页授权access_token失败");
			return null;
		}
	}
	
	/*
	 * @Description:获取访问的token(公众号、小程序通用，如果其他地方又使用appid和secret获取token，那么当前token5分钟后失效)
	 * 
	 * @param:
	 * 
	 */
	@SuppressWarnings("unchecked")
	public synchronized Map<String, Object> getAccessToken() {
		Map<String, Object> map = new HashMap<String, Object>();
		try {
			Map<String, Object> token = wxConfig.getCache("wxToken");
			if (token != null) {
				String access_token = (String) token.get("access_token");
				int expires_in = (Integer) token.get("expires_in");
				Date date = (Date) token.get("date");
				if (CalendarUtil.getDaySECOND(date, new Date()) + 1000 < expires_in) {
					// token在有效期内
					map.put("access_token", access_token);// 访问token
					map.put("expires_in", expires_in);// 过期时间
					map.put("flag", true);
					// log.info("从缓存中获取token------------------");
					return map;

				}
			}
			log.info("重新调用接口获取token------------------");
			token = new HashMap<String, Object>();
			access_query_token_url = access_query_token_url+"?grant_type=client_credential&appid="
					+ wxConfig.getAppID() + "&secret=" + wxConfig.getAppSecret();
			Map<String, Object> response = (Map<String, Object>) HttpClientUtil.httpJson
					.getClient(access_query_token_url, Charset.UTF8, Map.class);
			if (response.get("errcode") == null) {
				map.put("access_token", response.get("access_token"));// 访问token
				map.put("expires_in", response.get("expires_in"));// 过期时间
				map.put("date", new Date());// 添加时间
				wxConfig.putCache("wxToken", map);
				map.put("flag", true);
			} else {
				log.info(response.toString());
				map.put("flag", false);
			}

		} catch (Exception e) {
			log.info("获取访问的token失败");
			map.put("flag", false);
		}
		return map;
	}

	/*
	 * @Description:token失效则更新访问token(公众号、小程序通用)
	 * 
	 * @param:
	 * 
	 */
	@SuppressWarnings("unchecked")
	public void refreshAccessToken(int code) {
		try {
			if (code == 40001) {
				log.info("token失效，刷新token");
				// token失效，更新
				Map<String, Object> map = new HashMap<String, Object>();
				access_query_token_url = access_query_token_url+"?grant_type=client_credential&appid="
						+ wxConfig.getAppID() + "&secret=" + wxConfig.getAppSecret();
				Map<String, Object> response = (Map<String, Object>) HttpClientUtil.httpJson
						.getClient(access_query_token_url, Charset.UTF8, Map.class);
				if (response.get("errcode") == null) {
					map.put("access_token", response.get("access_token"));// 访问token
					map.put("expires_in", response.get("expires_in"));// 过期时间
					map.put("date", new Date());// 添加时间
					wxConfig.putCache("wxToken", map);
				} else {
					log.info(response.toString());
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

	}


	/*
	 * @Description:授权登录获取公众号用户信息(需scope为 snsapi_userinfo)
	 * 
	 * @param:
	 * 
	 * access_token:授权登录token openid：用户openId
	 * 
	 * @return:
	 * 
	 * openid 用户的唯一标识 nickname 用户昵称 sex 用户的性别，值为1时是男性，值为2时是女性，值为0时是未知 province
	 * 用户个人资料填写的省份 city 普通用户个人资料填写的城市 country 国家，如中国为CN headimgurl
	 * 用户头像，最后一个数值代表正方形头像大小（有0、46、64、96、132数值可选，0代表640*640正方形头像），用户没有头像时该项为空。
	 * 若用户更换头像，原有头像URL将失效。 privilege 用户特权信息，json 数组，如微信沃卡用户为（chinaunicom）
	 * unionid 只有在用户将公众号绑定到微信开放平台帐号后，才会出现该字段。
	 *
	 */
	@SuppressWarnings("unchecked")
	public Map<String, Object> getGzhOauth2UserInfo(String oauth2_token, String openid) {
		try {
			String url = userinfo_url + "?access_token=" + oauth2_token + "&openid=" + openid + "&lang=zh_CN";
			Map<String, Object> response = (Map<String, Object>) HttpClientUtil.httpJson.getClient(url, Charset.UTF8,
					Map.class);
			if (response.get("errcode") == null) {
				return response;
			} else {
				log.info(response.toString());
				return null;
			}
		} catch (Exception e) {
			log.error("获取用户微信信息失败");
			return null;
		}
	}

	/*
	 * @Description:获取已关注公众号用户信息
	 * 
	 * @return:
	 * 
	 * openid 用户的唯一标识 nickname 用户昵称 sex 用户的性别，值为1时是男性，值为2时是女性，值为0时是未知 province
	 * 用户个人资料填写的省份 city 普通用户个人资料填写的城市 country 国家，如中国为CN headimgurl
	 * 用户头像，最后一个数值代表正方形头像大小（有0、46、64、96、132数值可选，0代表640*640正方形头像），用户没有头像时该项为空。
	 * 若用户更换头像，原有头像URL将失效。 privilege 用户特权信息，json 数组，如微信沃卡用户为（chinaunicom）
	 * unionid 只有在用户将公众号绑定到微信开放平台帐号后，才会出现该字段。
	 *
	 */
	@SuppressWarnings("unchecked")
	public Map<String, Object> getGzhFocusUserInfo(String openid) {
		try {
			// 获取token
			Map<String, Object> token = getAccessToken();
			if ((Boolean) token.get("flag")) {
				String access_token = (String) token.get("access_token");
				String url = focus_user_url + "?access_token=" + access_token + "&openid=" + openid + "&lang=zh_CN";
				Map<String, Object> response = (Map<String, Object>) HttpClientUtil.httpJson.getClient(url,
						Charset.UTF8, Map.class);
				if (response.get("errcode") == null) {
					return response;
				} else {
					refreshAccessToken((Integer) response.get("errcode"));
					log.info(response.toString());
					return null;
				}
			} else {
				log.info("获取token失败");
				return null;
			}
		} catch (Exception e) {
			log.error("获取用户微信信息失败");
			return null;
		}
	}

	/*
	 * @Description:生成公众号带参数的二维码
	 * 
	 * @param:
	 * 
	 * access_token 微信token isforever 是否永久二维码 param 自定义参数，只能是整数或者字符串
	 *
	 */
	@SuppressWarnings({ "unchecked", "deprecation" })
	public String createGzhQrCode(boolean isforever, Object param) {
		try {
			// 获取token
			Map<String, Object> token = getAccessToken();
			if ((Boolean) token.get("flag")) {
				if ((Boolean) token.get("flag")) {
					String access_token = (String) token.get("access_token");
					String url = qr_code + access_token;
					Map<String, Object> request = new HashMap<String, Object>();
					Map<String, Object> actionInfo = new HashMap<String, Object>();
					Map<String, Object> scene = new HashMap<String, Object>();
					request.put("access_token", access_token);
					if (param instanceof Integer) {
						if (isforever) {
							request.put("action_name", "QR_LIMIT_SCENE");// 为永久的整型参数
						} else {
							request.put("action_name", "QR_SCENE");// 为临时的整型参数
							request.put("expire_seconds", 3600);
						}

						scene.put("scene_id", param);
					} else if (param instanceof String) {
						if (isforever) {
							request.put("action_name", "QR_LIMIT_STR_SCENE");// 为永久的字符串参数
						} else {
							request.put("action_name", "QR_STR_SCENE");// 为临时的字符串参数
							request.put("expire_seconds", 3600);
						}
						scene.put("scene_str", param);
					} else {
						log.info("参数只能是字符串或整数");

						return null;
					}
					actionInfo.put("scene", scene);
					request.put("action_info", actionInfo);
					Map<String, Object> response = (Map<String, Object>) HttpClientUtil.httpJson.postClient(url,
							request, Charset.UTF8, Map.class);
					if (response.get("errcode") == null) {
						String qrCodeUrl = qr_code_pic + URLEncoder.encode(response.get("ticket").toString());// 微信二维码图片链接
						return qrCodeUrl;
					} else {
						refreshAccessToken((Integer) response.get("errcode"));
						log.info(response.toString());
						return null;
					}
				} else {
					return null;
				}

			} else {
				log.info("获取token失败");
				return null;
			}

		} catch (Exception e) {
			log.info("获取用户微信二维码失败");
			return null;
		}
	}

	/*
	 * @Description:创建公众号菜单
	 * 
	 * @param:
	 * 
	 *
	 */
	@SuppressWarnings("unchecked")
	public void createGzhMenu() throws Exception {
		log.info("createMenu获取token");
		Map<String, Object> accessToken = getAccessToken();
		if ((Boolean) accessToken.get("flag")) {
			String url = create_wx_menu + accessToken.get("access_token");
			Map<String, Object> request = new HashMap<String, Object>();
			List<TreeMap<String, Object>> button = new ArrayList<TreeMap<String, Object>>();
			TreeMap<String, Object> button1 = new TreeMap<String, Object>();
			TreeMap<String, Object> button2 = new TreeMap<String, Object>();
			TreeMap<String, Object> button3 = new TreeMap<String, Object>();
			/* 菜单1配置 */
			button1.put("name", "减价抢拍");
			button1.put("type", "view");
			button1.put("url", "http://www.jianbid.com/public/index.html");

			/* 菜单2配置 */
			button2.put("name", "抢拍规则");
			button2.put("type", "click");
			button2.put("key", "43a888fc5cd1431a9ad254af0db8e573");

			/*
			 * 菜单2配置 List<TreeMap<String, Object>> button2list=new
			 * ArrayList<TreeMap<String, Object>>(); TreeMap<String, Object>
			 * button21=new TreeMap<String, Object>(); TreeMap<String, Object>
			 * button22=new TreeMap<String, Object>(); TreeMap<String, Object>
			 * button23=new TreeMap<String, Object>(); button21.put("name",
			 * "抢拍规则"); button21.put("type", "view"); button21.put("url",
			 * "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx96fe2dd6d8193e92&redirect_uri=http%3A%2F%2Fwww.eachpie.cn%2FgetUserCode.jhtml&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect"
			 * );
			 * 
			 * button22.put("name", "任务赚派币"); button22.put("type", "view");
			 * button22.put("url",
			 * "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx96fe2dd6d8193e92&redirect_uri=http%3A%2F%2Fwww.eachpie.cn%2Fwxweb%2FgetAccount.jhtml&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect"
			 * );
			 * 
			 * button23.put("name", "派币余额"); button23.put("type", "view");
			 * button23.put("url",
			 * "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx96fe2dd6d8193e92&redirect_uri=http%3A%2F%2Fwww.eachpie.cn%2FgetUserPie.jhtml&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect"
			 * );
			 * 
			 * button2list.add(button23); button2list.add(button22);
			 * button2list.add(button21);
			 * 
			 * button2.put("name", "我的派币"); button2.put("sub_button",
			 * button2list);
			 */

			/* 菜单3配置 */

			List<TreeMap<String, Object>> button3list = new ArrayList<TreeMap<String, Object>>();
			TreeMap<String, Object> button31 = new TreeMap<String, Object>();
			TreeMap<String, Object> button32 = new TreeMap<String, Object>();
			TreeMap<String, Object> button33 = new TreeMap<String, Object>();
			TreeMap<String, Object> button34 = new TreeMap<String, Object>();
			button31.put("name", "会员中心");
			button31.put("type", "view");
			button31.put("url", "http://www.jianbid.com/public/html/personal.html");

			button32.put("name", "在线客服");
			button32.put("type", "click");
			button32.put("key", "06bdacc35cd047efe79ddf1d551603cd");

			button33.put("name", "商家入驻");
			button33.put("type", "click");
			button33.put("key", "df3821d10b854fd596461dc63ce9a0a8");

			button34.put("name", "售后服务");
			button34.put("type", "click");
			button34.put("key", "43a888fc5cd1431a9ad254af0db8e571");

			button3list.add(button34);
			button3list.add(button33);
			button3list.add(button32);
			button3list.add(button31);

			button3.put("name", "我的服务");
			button3.put("sub_button", button3list);

			button.add(button1);
			button.add(button2);
			button.add(button3);

			request.put("button", button);
			Map<String, Object> response = (Map<String, Object>) HttpClientUtil.httpJson.postClient(url, request,
					Charset.UTF8, Map.class);
			log.info(response.toString());
		} else {
			log.info("获取token失败");
		}

	}

	/*
	 * @Description:删除公众号所有菜单
	 * 
	 * @param:
	 * 
	 *
	 */
	@SuppressWarnings("unchecked")
	public void delGzhMenu() throws Exception {
		log.info("delMenu获取token");
		Map<String, Object> accessToken = getAccessToken();
		if ((Boolean) accessToken.get("flag")) {
			String url = create_wx_menu + accessToken.get("access_token");
			Map<String, Object> response = (Map<String, Object>) HttpClientUtil.httpJson.getClient(url, Charset.UTF8,
					Map.class);
			log.info(response.toString());
		} else {
			log.info("获取token失败");
		}

	}

	/*
	 * @Description:发送公众号模板消息接口
	 * 
	 * @param:
	 * 
	 *
	 */
	@SuppressWarnings("unchecked")
	public void sendGzhMsg(String msg) throws Exception {
		log.info("sendMsg获取token");
		Map<String, Object> accessToken = getAccessToken();
		if ((Boolean) accessToken.get("flag")) {
			String url = send_msg + accessToken.get("access_token");
			Map<String, Object> response = (Map<String, Object>) HttpClientUtil.httpJson.postClient(url, msg,
					Charset.UTF8, Map.class);
			refreshAccessToken((Integer) response.get("errcode"));
		} else {
			log.info("获取token失败");
		}

	}

	/*
	 * @Description:发送公众号客服消息接口
	 * 
	 * @param:
	 * 
	 *
	 */
	@SuppressWarnings("unchecked")
	public void sendGzhCustomMsg(String msg) throws Exception {
		log.info("sendCustomMsg获取token");
		Map<String, Object> accessToken = getAccessToken();
		if ((Boolean) accessToken.get("flag")) {
			String url = custom_msg + accessToken.get("access_token");
			Map<String, Object> response = (Map<String, Object>) HttpClientUtil.httpJson.postClient(url, msg,
					Charset.UTF8, Map.class);
			refreshAccessToken((Integer) response.get("errcode"));
		} else {
			log.info("获取token失败");
		}

	}

	/*
	 * @Description:生成公众号授权登录短链接
	 * 
	 * @param:
	 * 
	 * scope: snsapi_userinfo ,snsapi_base 
	 * url: 跳转链接
	 * param:重定向后会带上state参数，开发者可以填写a-zA-Z0-9的参数值，最多128字节
	 * 
	 *
	 */
	@SuppressWarnings("deprecation")
	public String createGzhAuthorizeUrl(String scope, String url, String param) {
		try {
			url = URLEncoder.encode(url);
			String location = authorizeUrl+"?appid=" + wxConfig.getAppID()
					+ "&redirect_uri=" + url + "&response_type=code&scope=" + scope + "&state=" + param
					+ "#wechat_redirect";
			return gzhShorturl(location);
		} catch (Exception e) {
			return "";
		}
	}

	/*
	 * @Description:公众号长链接转短链接接口
	 * 
	 * @param:
	 * 
	 *
	 */
	@SuppressWarnings("unchecked")
	public String gzhShorturl(String long_url) throws Exception {
		Map<String, Object> accessToken = getAccessToken();
		if ((Boolean) accessToken.get("flag")) {
			String url = shorturl + accessToken.get("access_token");
			Map<String, Object> request = new HashMap<String, Object>();
			request.put("action", "long2short");
			request.put("long_url", long_url);
			Map<String, Object> response = (Map<String, Object>) HttpClientUtil.httpJson.postClient(url, request,
					Charset.GBK, Map.class);
			int code = (Integer) response.get("errcode");
			if (code == 0) {
				return (String) response.get("short_url");
			} else {
				refreshAccessToken((Integer) response.get("errcode"));
				log.info(response.toString());
				return "";
			}
		} else {
			log.info("shorturl获取token失败");
			return "";
		}

	}

	
	/*
	 * @Description:获取公众号JS接口的临时票据
	 * 
	 * @param:
	 * 
	 */
	@SuppressWarnings("unchecked")
	public Map<String, Object> getGzhJsapiTicket() {
		Map<String, Object> map = new HashMap<String, Object>();
		try {
			Map<String, Object> ticket = wxConfig.getCache("wxTicket");
			if (ticket != null) {
				String access_ticket = (String) ticket.get("access_ticket");
				int expires_in = (Integer) ticket.get("expires_in");
				Date date = (Date) ticket.get("date");
				if (CalendarUtil.getDaySECOND(date, new Date()) + 1000 < expires_in) {
					// ticket在有效期内
					map.put("access_ticket", access_ticket);// 访问ticket
					map.put("expires_in", expires_in);// 过期时间
					map.put("flag", true);
					return map;
				}
			}
			log.info("重新调用接口获取ticket------------------");
			ticket = new HashMap<String, Object>();
			Map<String, Object> accessToken = getAccessToken();
			if ((Boolean) accessToken.get("flag")) {
				String url = jsapi_ticket + accessToken.get("access_token");
				Map<String, Object> response = (Map<String, Object>) HttpClientUtil.httpJson.getClient(url,
						Charset.UTF8, Map.class);
				int code = (Integer) response.get("errcode");
				if (code == 0) {
					map.put("access_ticket", response.get("ticket"));// 访问token
					map.put("expires_in", response.get("expires_in"));// 过期时间
					map.put("date", new Date());// 添加时间
					wxConfig.putCache("wxTicket", map);
					map.put("flag", true);
				} else {
					log.info(response.toString());
					map.put("flag", false);
				}
			} else {
				log.info("获取token失败");
				map.put("flag", false);
			}

		} catch (Exception e) {
			log.info("获取访问的ticket失败");
			map.put("flag", false);
		}
		return map;
	}
	/*
	 * @Description:下载微信JSSDK上传的临时文件（公众号、小程序通用）
	 * 
	 * @param: media_id:微信临时文件id
	 *
	 */
	public File getFile(String media_id, String savePath, String fileName) throws Exception {
		Map<String, Object> accessToken = getAccessToken();
		try {
			if ((Boolean) accessToken.get("flag")) {
				String url = getFileUrl + accessToken.get("access_token") + "&media_id=" + media_id;
				try {
					HttpClientUtil.httpJson.getClient(url, Charset.UTF8, Map.class);
					return null;
				} catch (Exception e) {
					// log.info(url);
					File file = FileUtil.downLoadWebFile(url, savePath, fileName);
					return file;
				}
			} else {
				log.info("获取token失败");
				return null;
			}
		} catch (Exception e) {
			return null;
		}

	}

	/*
	 * @Description:下载公众号JSSDK上传的高清临时语音文件
	 * 
	 * @param: media_id:微信临时文件id
	 *
	 */
	public File getGzhNiceFile(String media_id, String savePath, String fileName) throws Exception {
		Map<String, Object> accessToken = getAccessToken();
		try {
			if ((Boolean) accessToken.get("flag")) {
				String url = getNiceFileUrl + accessToken.get("access_token") + "&media_id=" + media_id;
				if (url.contains("errcode")) {
					return null;
				}
				log.info(url);
				File file = FileUtil.downLoadWebFile(url, savePath, fileName);
				return file;
			} else {
				log.info("获取token失败");
				return null;
			}
		} catch (Exception e) {
			return null;
		}

	}
	
	
	
	//-------------------------------------------------小程序模块-------------------------------------------------------------
	/*
	 * @Description:使用code获取微信小程序session_key
	 * 
	 * @return
	 * 
	 * "openid": "OPENID", 
	 * "session_key": "SESSIONKEY",
	 * "unionid":"UNIONID"(在满足UnionID下发条件的情况下)
	 * 
	 *
	 */
	@SuppressWarnings("unchecked")
	public Map<String, Object> xcxJscode2session(String code) throws Exception {
		String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + wxConfig.getAppID() + "&secret="
				+ wxConfig.getAppSecret() + "&js_code=" + code + "&grant_type=authorization_code";
		//log.info(url);
		Map<String, Object> response = (Map<String, Object>) HttpClientUtil.httpJson.getClient(url, Charset.UTF8,
				Map.class);
		if (response.get("errcode") == null) {
			return response;
		} else {
			log.info("使用code获取微信小程序信息失败：" + response);
			return null;
		}

	}

	/*
	 * @Description:获取小程序二维码
	 * 
	 * @param:
	 * 
	 * scene:二维码参数值(最大32个可见字符，只支持数字，大小写英文以及部分特殊字) 是 page:跳转页面路径 是 width:二维码的宽度 否
	 * 
	 */
	public File getXcxQrcode(Map<String, Object> param, String filePath) throws Exception {
		Map<String, Object> accessToken = getAccessToken();
		if ((Boolean) accessToken.get("flag")) {
			String url = getwxacodeunlimit + accessToken.get("access_token");
			File file = HttpClientUtil.httpJson.postClientReturnFile(url, param, Charset.UTF8, filePath);
			return file;
		} else {
			log.info("获取token失败");
			return null;
		}

	}

	/*
	 * @Description:发送微信小程序模板消息
	 * 
	 * @param:
	 * 
	 *
	 */
	@SuppressWarnings("unchecked")
	public void sendXcxMsg(Map<String, Object> msg) throws Exception {
		Map<String, Object> accessToken = getAccessToken();
		if ((Boolean) accessToken.get("flag")) {
			String url = send_mic_msg + accessToken.get("access_token");
			Map<String, Object> response = (Map<String, Object>) HttpClientUtil.httpJson.postClient(url, msg,
					Charset.UTF8, Map.class);
			refreshAccessToken((Integer) response.get("errcode"));
		} else {
			log.info("获取token失败");
		}

	}

	/*
	 * @Description:微信小程序用户信息解密
	 * 
	 * @param:
	 * encryptedData:加密数据
	 * iv:加密矢量
	 * sessionKey:会话密钥（小程序登录接口获取）
	 *
	 */
	public static String decryptXcxUserInfo(String encryptedData,String iv,String sessionKey) throws Exception {
		AES aes = new AES();
		byte[] resultByte = aes.decrypt(Base64.decode(encryptedData), Base64.decode(sessionKey),Base64.decode(iv));
		if (null != resultByte && resultByte.length > 0) {
			return new String(WxXcxPKCS7Encoder.decode(resultByte));
		}else {	
			//用户信息解析失败
			return null;
		}
	}

	
}
